#ifndef CFILESYSTEM_H
#define CFILESYSTEM_H

#include <QImage>
#include <list>
#include <string.h>
//#include "CHardwareFacade.h"
#include "CHardwareParams.h"

using namespace std;

//===================================================================
//
//      TYPE DEFINITIONS
//
//===================================================================
typedef unsigned char                   BYTE;
typedef unsigned short                  WORD;
typedef list<class CFile>               file_list_t;
typedef list<CFile>::iterator           file_list_it_t;



//===================================================================
//
//      ENUMS AND DEFINES
//
//===================================================================

// Enums
enum {
    FILE_SYSTEM_NO_ERROR    = 0,
    FILE_SYSTEM_ALLOCATION_ERROR,
    FILE_SYSTEM_MAX_FRAME_REACHED_ERROR,
    FILE_SYSTEM_NO_FRAMES_WERE_FOUND_ERROR,
    FILE_SYSTEM_FILE_NOT_FOUND_ERROR,
    FILE_SYSTEM_FILE_ALREADY_EXISTS_ERROR,
    FILE_SYSTEM_PARSE_ERROR,
    FILE_SYSTEM_ILLEGAL_MEMORY_BLOCK,
    FILE_SYSTEM_ILLEGAL_FILE_NAME,
    FILE_SYSTEM_RECOVERRED_FROM_NONUNIQUE,
    FILE_SYSTEM_COULDNT_RECOVER_NONUNIQUE,
    FILE_SYSTEM_FRAME_DOESNT_EXIST,
    FILE_SYSTEM_MAX_ERROR
};

typedef enum {
    FILE_SYSTEM_MEMVAC_EMPTY    = 0,
    FILE_SYSTEM_MEMVAC_USED,
    FILE_SYSTEM_MEMVAC_DELETED,
    FILE_SYSTEM_MEMVAC_OVERWRITTEN,
    FILE_SYSTEM_MEMVAC_NEEDS_UPDATE_TABLE,
    FILE_SYSTEM_MEMVAC_NEEDS_UPDATE_FRAMES

} FILE_SYSTEM_MEMVAC_STATUS_EN;

typedef enum {
    FILE_SYSTEM_FIND_FOR_DELETION = 0,
    FILE_SYSTEM_FIND_FOR_UPDATING = 0,
    FILE_SYSTEM_FIND_FOR_NEW_SLOT = 0

} FILE_SYSTEM_FIND_PURPOSE_EN;




//===================================================================
//
//      CFRAME CLASS
//
//===================================================================

class CFrame
{
public:
    CFrame (int bufferSize = 0);
    CFrame (CFrame& frame);
    ~CFrame ();

    void SetData(int bufferSize, BYTE* buffer);

    int NumOfBytes ();

public:
    int m_BufferSize;
    BYTE* m_buffer;
};



//===================================================================
//
//      CFILE CLASS
//
//===================================================================

class CFile
{
public:
    CFile();
    CFile(CHardwareParams* hwParams,
          char *fileName,
          int duration = 255);
    CFile(const CFile& file);
    ~CFile();

    void SetData(CHardwareParams* hwParams,
                 char *fileName,
                 int duration = 256);
    int FileSize();

    int AddFrame(int blockNumber, CFrame &frame);
    int AddFrame(int blockNumber,BYTE* buffer, int bufferSize);
    int DeleteLastFrame();
    int SetFrameData(int frameIndex, BYTE* buffer, int bufferSize);
    void InvalidateTable();
    void IntermediateValidateTable();
    int GetValidity();
    int GetNumOfFrames ( void );
    int GetFrameData(int frameNum, int* length, unsigned char **data);
    int GetEntrySize();
    void SetDownloadingState ( int downloading );
    int GetDownloadingState ( void );

    bool operator==(const CFile& file);

    void setOriginalImage (QImage& image);
    QImage* getOriginalImage ( void );

public:
    /* ENTRY SCTRUCTURE:
       -----------------
       WORD num_of_blocks;
       CHAR file_name[hw->file_name_length];
       WORD block_list[hw->max_num_of_frames];
       BYTE duration;
       BYTE reserved;                               // in moussavi this is width
    */

    BYTE m_Duration;
    char *m_FileName;
    WORD *m_BlockList;
    WORD m_NumOfFrames;
    BYTE m_Reserved;                                // in moussavi this is width

    int m_TableNeedsUpdate;
    int m_ContentsAvailable;
    int m_isDownloading;

    CHardwareParams* m_HWParams;

    CFrame *m_Buffers;

    QImage *m_originalImage;
};



//===================================================================
//
//      CFILESYSTEM CLASS
//
//===================================================================

class CFileSystem
{
public:
    CFileSystem(CHardwareParams *hwParams);
    CFileSystem(const CFileSystem& fs);
    ~CFileSystem();

    void DeleteFileSystemData();
    CFile* SearchFile(char* filename, list<CFile>::iterator* fileIt = NULL);
    int AddFile(char* filename, int param = 128);       // param is "width" for moussavi
                                                        // reserved for all others
    int AddFile(CFile file);

    int AddFrameToFile(char* filename, CFrame& frame);
    int AddFrameToFile(char* filename, int bufferSize, BYTE* buffer);
    int SetFileDuration(char* filename, int duration);
    int ChangeFileName (char* oldFilename, char* newFilename);
    int DeleteLastFrameFromFile(char* filename);
    int DeleteFileFS(char* filename);
    int GetFileFrameData(char* filename, int frameNum, int *length, unsigned char** data);
    int GetEntryTableData(int *length, unsigned char ** data);

    int GetNumOfFiles ( void );
    file_list_it_t GetFileFromIndex ( int fileIndex );

    FILE_SYSTEM_MEMVAC_STATUS_EN GetMemVec(int index);

    file_list_t& GetFileList();

    int ParseFromRawFS(BYTE* data, int length);
    int GetEntryTableStartAddress ();

    void SetAllFilesSynchronized ( void );

    void SetOriginalImageToFile (char* filename, QImage& image);
    QImage* GetOriginalImageToFile (char* filename);

private:
    CHardwareParams* m_HWParams;
    int m_MemorySizeBytes;
    int m_MaxFiles;
    int m_MaxFileSize;
    int m_EntryTableStartAddress;
    file_list_t m_Files;
    int *m_MemVac;

private:
    int FindMemorySlot(FILE_SYSTEM_FIND_PURPOSE_EN purpose);
    int SuggestFilename(char* wantedFilename, char* suggestedFilename);
};

#endif // CFILESYSTEM_H
